package com.yuye.java.redis.template.jedis;

import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.function.Function;

import com.yuye.java.redis.template.RedisHotspotData;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;

import lombok.extern.slf4j.Slf4j;
import redis.clients.jedis.GeoCoordinate;
import redis.clients.jedis.GeoUnit;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.params.SetParams;

/**
 * Jedis工具类
 *
 * @author gzs
 */
@Slf4j
public class JedisRepository implements RedisHotspotData {
	
	private static final int DEFAULT_EXIST_SENCONDS = 3000;

	private static final String OK = "OK";
	 @Autowired
	 private JedisPool jedisPool;
	 
	 private static final ThreadLocal<Jedis> JEDIS_THREAD_LOCAL = new ThreadLocal<Jedis>();
	 
	 private Jedis common() {
//		 if(JEDIS_THREAD_LOCAL.get() == null) {
//			 JEDIS_THREAD_LOCAL.set(jedisPool.getResource());
//		 }
//		 return JEDIS_THREAD_LOCAL.get();
		 return jedisPool.getResource();
	 }

	/**
	 * 移除jedis线程
	 */
	public static void remove(){
		JEDIS_THREAD_LOCAL.remove();
	}

	 /**
	  * 
	  * 分布式锁的简单应用
	  *
	  * @author xgf
	  * @param key 分佈式鎖 的key
	  * @param value 分佈式鎖 的value
	  * @return Boolean true加锁成功 false 加锁失败
	  */
	 @Override
	 public Boolean setnx(String key, String value) {
		 Jedis jedis = common();
//		 String result = jedis.set("lock_test", "value_test", SetParams.setParams().nx());
		 String result = jedis.set(key, value, SetParams.setParams().nx());
		 System.out.println(result);
		 if(result != null && OK.equals(result)) {
			 return true;
		 }
		 return false;
	 }
	 
	 /**
	  * jedis 删除指定标识
	  * @param key 处理的redis key
	  * @return Long 返回值
	  */
	 @Override
	 public Long del(String key) {
		 Jedis jedis = common();
		 Long  result = jedis.del(key);
		 return result;
	 }

	@Override
	 public Boolean mset(String... content) {
		 Jedis jedis = common();
		 String mset = jedis.mset(content);
		 System.out.println(mset);
		 return false;
	 }

	@Override
	 public List<String> mget(String... keys) {
		 Jedis jedis = common();
		 return jedis.mget(keys);
	 }

	@Override
	 public Boolean msetnx(String... content) {
		 Jedis jedis = common();
		 Long msetnx = jedis.msetnx(content);
		 System.out.println(msetnx);
		 if(msetnx > 0) {
			 return true;
		 }
		 return false;
	 }
	 
	 /**
	  * 
	  * 获取长度
	  * 应用场景： 获取博客 内容长度
	  *
	  * @author xgf
	  * @param key redis的key
	  * @return Long类型 内容长度
	  */
	 @Override
	 public Long strlen(String key) {
		 Jedis jedis = common();
		 return jedis.strlen(key);
	 }

	@Override
	 public String getRange(String key, int startOffset, int endOffset) {
		 Jedis jedis = common();
		 return jedis.getrange(key, startOffset, endOffset);
	 }
	 
	 /**
	  * 拼接字符串
	  * 应用场景：
	  *   可实现审计日志的记录
	  *
	  * @author xgf
	  * @param key 键
	  * @param value 值
	  * @return Boolean true添加成功 false 添加失败
	  */
	 @Override
	 public Boolean append(String key, String value) {
		 Jedis jedis = common();
		 Long append = jedis.append(key, value);
		 if(append >= 0) {
			 return true;
		 }
		 return false;
	 }
	 
	 /**
	  * key的value 添加1
	  * 可能问题：
	  *    key是已经存在的
	  *    redis.clients.jedis.exceptions.JedisDataException: ERR value is not an integer or out of range
	  *
	  * @author xgf
	  * @param key 键
	  * @return Long类型 增加后的value
	  */
	 @Override
	 public Long incr(String key) {
		 Jedis jedis = common();
		 Long result = jedis.incr(key);
		 return result;
	 }

	@Override
	 public Long incrBy(String key, Long incr) {
		 Jedis jedis = common();
		 Long result = jedis.incrBy(key, incr);
		 return result;
	 }

	@Override
	 public Long decr(String key) {
		 Jedis jedis = common();
		 Long result = jedis.decr(key);
		 return result;
	 }

	@Override
	 public Long hset(String key, String field, String value) {
		 Jedis jedis = common();
		 Long result = jedis.hset(key, field, value);
		 return result;
	 }

	@Override
	 public Long hincrBy(String key, String field, Long value) {
		 Jedis jedis = common();
		 Long result = jedis.hincrBy(key, field, value);
		 return result;
	 }

	@Override
	 public String hget(String key, String field) {
		 Jedis jedis = common();
		 String result = jedis.hget(key, field);
		 return result;
	 }
	 
	 /**
	  * 
	  * 获取hash数据结构下 value的值
	  *
	  * @author xgf
	  * @param key 要获取的key
	  * @return Map value值
	  */
	 @Override
	 public Map<String, String> hgetAll(String key) {
		 Jedis jedis = common();
		 Map<String, String> result = jedis.hgetAll(key);
		 return result;
	 }

	@Override
	 public String get(String key) {
		 Jedis jedis = common();
		  try {
			  String result = jedis.get(key);
			  return result;
			} finally {
				if (jedis != null){
				    jedis.close();
				}
			}
			
			 
	 }
	 
	 /**
	  * 防止 缓存穿透的 查询  会预留一个空值 防止 多次查询
	  * @param key 缓存查询的key
	  * @return 有值 就直接返回 没有就返回空值
	  */
	 @Override
	 public String getForPierceThrough(String key) {
		 String result = get(key);
		 if(StringUtils.isBlank(result)) {
			  set(key, DEFAULT_EXIST_SENCONDS, result);
		  }
		  return result;
	 }

	@Override
	public String set(String key, String field) {
		if(StringUtils.isBlank(field)) {
			log.error(" set field is not empty  key: [{}]", key);
			return "";
		}
		Jedis jedis = common();
		 
		 
		try {
			  String result = jedis.set(key, field);
			  return result;
		} finally {
			if (jedis != null){
			    jedis.close();
			}
		}
			
	}

	@Override
	public String set(String key,int senconds, String field) {
		Jedis jedis = common();
		try {
			String result = jedis.setex(key,getRandomTimeOut(senconds), field);
			  return result;
		} finally {
			if (jedis != null){
			    jedis.close();
			}
		}
		 
	}
	
	
	/**
	 * 为了防止缓存雪崩 对超时时间 添加盐
	 * @param senconds  默认的超时时间 单位s
	 * @return 加盐之后的超时时间
	 */
	private Integer getRandomTimeOut(int senconds) {
		Random random = new Random(1800);
		return senconds + random.nextInt();
		
	}
	
	/**
	 * 
	 * 执行数据库的操作 
	 * 例如：
	 *    insert
	 *    update
	 *
	 * @author xgf
	 * @param key 键
	 * @param params map
	 * @param f Function
	 * @return Object
	 */
	@Override
	public Object executeDataBaseHandle(String key,Map<String, Object> params, Function<Map<String, Object>, Object> f) {
		String string = get(key);
		if(StringUtils.isNotBlank(string)) {
			return string;
		}
		Object apply = f.apply(params);
		if(apply == null) {
			set(key, DEFAULT_EXIST_SENCONDS, null);
		}
		return apply;
	}
	
	/**
	 * 
	 * 从左边放数据 list数据结构
	 *
	 * @author xgf
	 * @param key key值
	 * @param value 要存的string 数组对象
	 * @return Long 成功多少条
	 */
	@Override
	public Long lpush(String key, String... value) {
		Jedis jedis = common();
		Long result = jedis.lpush(key, value);
		return result;
	}
	
	/**
	 * 
	 * 从右边弹出数据 list数据结构
	 *
	 * @author xgf
	 * @param key 要获取的key值
	 * @return String 返回的value
	 */
	@Override
	public String rpop(String key) {
		Jedis jedis = common();
		String result = jedis.rpop(key);
		return result;
	}

	@Override
	public Long zadd(String key, Double score,  String member) {
		Jedis jedis = common();
		Long result = jedis.zadd(key, score, member);
		return result;
	}
	
	/**
	 * 
	 * zscore 获取当前value的分数
	 *
	 * @author xgf
	 * @param key redis的sort set key
	 * @param member 要查询的 value
	 * @return Double 当前value的分数
	 */
	@Override
	public Double zscore(String key,  String member) {
		Jedis jedis = common();
		Double result = jedis.zscore(key, member);
		return result;
	}
	
	/**
	 * 
	 * zrem sort set 删除操作
	 *
	 * @author xgf
	 * @param key redis的sort set key
	 * @param member 要删除的value 集合
	 * @return Long 被成功移除的成员的数量
	 */
	@Override
	public Long zrem(String key,  String... member) {
		Jedis jedis = common();
		Long result = jedis.zrem(key, member);
		return result;
	}
	
	/**
	 * 
	 * zincrby 分数修改
	 *
	 * @author xgf
	 * @param key redis的sort set key
	 * @param score 要修改的分数
	 * @param member 要处理的value 集合
	 * @return Double 修改之后的分数
	 */
	@Override
	public Double zincrby(String key,  Double score, String member) {
		Jedis jedis = common();
		Double result = jedis.zincrby(key, score, member);
		return result;
	}
	
	/**
	 * 
	 * 获取排名 默认从0开始
	 *
	 * @author xgf 
	 * @param key redis的sort set key
	 * @param member 要处理的value
	 * @return Long 当前该条的排名
	 */
	@Override
	public Long zrevrank(String key,  String member) {
		Jedis jedis = common();
		Long result = jedis.zrevrank(key, member);
		return result;
	}
	
	/**
	 * 
	 * zrevrange 分页获取排行榜
	 *
	 * @author xgf
	 * @param key redis的sort set key
	 * @param start 分页的开始
	 * @param stop  分页的结束
	 * @return 返回的分页数据
	 */
	@Override
	public Set<String> zrevrange(String key,  long start, long stop) {
		Jedis jedis = common();
		Set<String> result = jedis.zrevrange(key, start, stop);
		return result;
	}
	
	/**
	 * 
	 * 应用例子：基于位图的网站用户行为 记录
	 *
	 * @author xgf
	 * @param key setbit的 key 一般根据业务设置
	 * @param offset 偏移量 可以是用户id 或者id
	 * @param value 设置的通用值 默认是 字符串的1
	 * @return Boolean true 是 设置 成功 false 是 设置失败
	 */
	@Override
	public Boolean setbit(String key,  long offset, String value) {
		Jedis jedis = common();
		Boolean result = jedis.setbit(key, offset, value);
		return result;
	}
	
	/**
	 * 
	 * getbit 获取 是否存在过
	 *
	 * @author xgf
	 * @param key getbit的 key 一般根据业务设置
	 * @param offset  偏移量 可以是用户id 或者id
	 * @return Boolean true 是 存在 false 是 不存在该数据
	 */
	@Override
	public Boolean getbit(String key,  long offset) {
		Jedis jedis = common();
		Boolean result = jedis.getbit(key, offset);
		return result;
	}

	@Override
	public Long geoadd( String key,  Map<String, GeoCoordinate> memberCoordinateMap) {
		Jedis jedis = common();
		Long result = jedis.geoadd(key, memberCoordinateMap);
		return result;
	}

	@Override
	public Double geodist( String key,  String member1,  String member2,  GeoUnit unit) {
		Jedis jedis = common();
		Double result = jedis.geodist(key, member1, member2, unit);
		return result;
	}
	
}
